#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <queue>
#include <algorithm>
#define REP(i,n) for(int i=0;i<int(n);++i)
using namespace std;
const int inf = 1<<29;
struct Edge
{
    int vs,vt,flow,cap;
    Edge *next;
    void set(int a,int b,int w)
    {
    	vs=a,vt=b,cap=w;
    	flow=0;
    }
    inline int remain()
    {
    	return cap-flow;
    }
};

class Graph
{
    static const int MVN=20200,MARCN= 200200*4+MVN*4;
public:
    int vn,arcn;
    Edge *edge,*head[MVN];
    Graph(int n=0)
    {
        init(n);
        edge=new Edge[MARCN];
    };
    void init(int n)
    {
        vn=n;
        arcn=0;
        fill(head,head+n+1,(Edge*)NULL);
    }
    void add(int vs,int vt,int cap)
    {
        edge[arcn].set(vs,vt,cap);
        edge[arcn].next=head[vs];
        head[vs]=&edge[arcn++];
    }
    void addEdge(int vs,int vt,int cap)
    {
    	add(vs,vt,cap);
    	add(vt,vs,0);
    }
    int maxFlow(int vs,int vt)
    {
        int dist[MVN],cnt[MVN],ans=0;
        Edge *pre[MVN],*cur[MVN];
        for(int i=0;i<=vn;i++)
        {
        	cnt[i]=dist[i]=0;
        	pre[i]=NULL;
        	cur[i]=head[i];
        }
        cnt[0]=vn;
        int pos=vs;
        Edge *ep;
        while (dist[vs]<vn)
        {
        	for(ep=cur[pos];ep;ep=ep->next) if(dist[pos]==dist[ep->vt]+1&&ep->remain()) break;
        	if(ep)
        	{
        		cur[pos]=ep; pre[ep->vt] = ep;
        		pos=ep->vt;
        		if(pos==vt)
        		{
        			int minf=inf;
        			for(ep=pre[vt];ep;ep=pre[ep->vs]) if(ep->remain()<minf)
        			{
        				minf=ep->remain();
        				pos=ep->vs;
        			}
        			for(ep=pre[vt];ep;ep=pre[ep->vs])
        			{
        				ep->flow+=minf;
        				edge[(ep-edge)^1].flow-=minf;
        			}
        			ans+=minf;
        		}
        	}
        	else
        	{
        		if(--cnt[dist[pos]]==0) break;
        		dist[pos]=vn;
        		for(ep=head[pos];ep;ep=ep->next) if(dist[pos]>dist[ep->vt]+1&&ep->remain())
        			dist[pos]=dist[ep->vt]+1,cur[pos]=ep;
				cnt[dist[pos]]++;
				if(pos!=vs) pos=pre[pos]->vs;
        	}
        }
        return ans;
    }
};

Graph g;
int map[60][60];

int main()
{
    int m,n;
    while(cin>>m>>n)
    {
        int sum = 0;
        g.init(m*n+10);
        int ss = m*n+4,tt = ss + 1;
        REP(i,m) REP(j,n) cin>>map[i][j],sum+=map[i][j];
        REP(i,m) REP(j,n)
        {
            if((i+j)&1)
            {
                g.addEdge(i*n+j,tt,map[i][j]);
                if(j+1<n) g.addEdge(i*n+j+1,i*n+j,inf);
                if(i+1<m) g.addEdge((i+1)*n+j,i*n+j,inf);
            }
            else
            {
                g.addEdge(ss,i*n+j,map[i][j]);
                if(j+1<n) g.addEdge(i*n+j,i*n+j+1,inf);
                if(i+1<m) g.addEdge(i*n+j,(i+1)*n+j,inf);
            }
        }
        cout<<sum-g.maxFlow(ss,tt)<<endl;
    }
	return 0;
}
